//
// Created by lihengliu on 2023/3/1.
//
#include <jni.h>
#include <string>
#include <vector>

//单链表
#include <forward_list>

//双链表
#include <list>

//map
#include <map>

//unordered_map 一键可以对应多值
#include <unordered_map>

//set
#include <set>

#include<android/log.h>

#include "util/jni_simple_data_swap.h"
#include "util/jni_string_convert_util.h"

using namespace std;

#define LOG_TAG "CPLUSPLUS_TAG"
#define LOG_D(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

///////////////////////////////////////////////////////////////////////////////////////
//封装Log日志
void printValue(int a) {
    LOG_D("%d\n", a);
}

void printValue(int a,int b) {
    LOG_D("%d,%d\n", a, b);
}

void printValue(const char * a) {
    LOG_D("%s\n", a);
}

void printValue(const string& a) {
    LOG_D("%s\n", a.c_str());
}
///////////////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////////////
//自定义结构体
typedef struct Point {
 public:
    int x;
    int y;
    Point(int x,int y) {
        this->x = x;
        this->y = y;
    }
    friend bool operator==(Point &a, Point &b) {
        return a.x == b.x && a.y == b.y;
    }
} Point;
///////////////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////////////
//模板函数
template<class T> void swapValue(T &a,T &b) {
    T temp = a;
    a = b;
    b = temp;
}
///////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////
//类模板
template<class T1,class T2> class Person {
   public:
    T1 value;
    T2 data;

    Person(T1 value, T2 data) {
        this->value = value;
        this->data = data;
    }
};
///////////////////////////////////////////////////////////////////////////////////////

extern "C" JNIEXPORT jint JNICALL Java_com_hengfoxwolf_jnidemo_CPlusPlusLearnActivity_getValueFromJNI
(JNIEnv *env,
 jobject thiz,
 jint a,
 jint b) {

    jint va = 5;
    jint vb = 10;
    SimpleDataSwap::swapValue(va, vb);
    printValue(va, vb);

    //向量的使用
    vector<int> container;
    for (int i = 0; i < 10; ++i) {
        container.push_back(i);
    }

    for(auto &value : container) {
        printValue(value);
    }

    printValue("============================================");
    //更新值 --通过begin()追加偏移量或end()
    container.insert(container.begin() + 6, 100);
    container.insert(container.end(), 50);
    //删除
    container.erase(container.begin() + 2);

    for (auto value = container.begin(); value != container.end(); value++) {
        printValue(*value);
    }

    printValue("============================================");

    //string对象使用
    string str = "1234567";
    str += "890";
    printValue(str.c_str());

    printValue("============================================");

    //赋值给另一个vector
    vector<int> other;
    other.assign(container.begin(), container.end());
    for(auto &value : other) {
        printValue(value);
    }

    printValue("useSwap============================================useSwap");

    vector<int> useSwap;
    //把数据转移到useSwap 并清空 container
    useSwap.swap(container);
    for(auto &value : other) {
        printValue(value);
    }


    printValue("Point============================================Point");
    Point point0(10, 5);
    Point point1(11, 15);
    Point point2(20, 65);
    Point point3(30, 55);
    Point point4(10, 5);
    vector<Point> pointVector;

    pointVector.push_back(point0);
    pointVector.push_back(point1);
    pointVector.push_back(point2);
    pointVector.push_back(point3);
    pointVector.push_back(point4);

    for (auto &point: pointVector) {
        LOG_D("v0:%d,v1:%d\n", point.x, point.y);
    }

    LOG_D("equals:%i\n",point1 == point4);

    return 5;
}


extern "C"
JNIEXPORT void JNICALL
Java_com_hengfoxwolf_jnidemo_CPlusPlusLearnActivity_forwardlistUseFromJNI(JNIEnv *env, jobject thiz) {

    //单链表
    forward_list<int> forward_list_data;

    int count = 10;
    for (int i = 0; i < count; ++i) {
        forward_list_data.push_front(i + count);
    }
    //反转
    forward_list_data.reverse();

    printValue("forward_list_data===========================================forward_list_data");
    //foreach遍历
    //for (auto &value: forward_list_data) {
    //    printValue(value);
    //}

    //迭代器遍历
    forward_list_data.insert_after(forward_list_data.begin(), 300);
    for (auto value = forward_list_data.begin(); value != forward_list_data.end(); value++) {
        printValue(*value);
    }

    printValue("newDataSet===========================================newDataSet");

    forward_list<int> newDataSet;
    //转移元素到另外一个列表   当前列表清空
    newDataSet.swap(forward_list_data);
    //删除元素
    newDataSet.erase_after(newDataSet.begin());
    for (auto value = newDataSet.begin(); value != newDataSet.end(); value++) {
        printValue(*value);
    }

    if(forward_list_data.empty()) {
        printValue(0);
    } else {
        printValue(1);
    }
}


extern "C"
JNIEXPORT void JNICALL
Java_com_hengfoxwolf_jnidemo_CPlusPlusLearnActivity_listUseFromJNI(JNIEnv *env, jobject thiz) {

    //双向列表
    list<int> dataSet;
    int count = 10;
    for (int i = 0; i < count; i++) {
        dataSet.push_back(i);
    }

    printValue("dataSet===========================================dataSet");

    for (auto value = dataSet.begin(); value != dataSet.end(); value++) {
        printValue(*value);
    }

    printValue("otherSet===========================================otherSet");

    list<int> otherSet = {20, 21, 22, 23, 24, 25, 26};
    otherSet.erase(otherSet.begin());
    //不能删除最后一个
    //otherSet.erase(otherSet.end());
    for (auto value = otherSet.begin(); value != otherSet.end(); value++) {
        printValue(*value);
    }

    //其他的api与forward_list大致相同
}


extern "C"
JNIEXPORT void JNICALL
Java_com_hengfoxwolf_jnidemo_CPlusPlusLearnActivity_mapUseFromJNI(JNIEnv *env, jobject thiz) {

    //map容器  map的键是唯一的,值可以相同,存在相同的键,后面的会覆盖前面的.
    map<int, string> container;
    container[0] = "a";
    container[0] = "b";
    container[2] = "c";
    container[3] = "c";

    printValue("map11===========================================map11");

    //迭代器
    for (auto value = container.begin(); value != container.end(); value++) {
        printValue(value->first);
        printValue(value->second);
    }

    printValue("map22===========================================map22");

    //foreach
    for (auto &value : container) {
        printValue((&value)->first);
        printValue((&value)->second);
    }

    container.erase(container.begin());
    //不能删除最后一个
    //container.erase(container.end());
    printValue("map33===========================================map33");

    //foreach
    for (auto &value : container) {
        printValue((&value)->first);
        printValue((&value)->second);
    }

    map<int, string> new_container;
    //swap() 把A中的所有元素到B容器,A则清空.
    new_container.swap(container);

    printValue("map44===========================================map44");

    //foreach
    for (auto &value : new_container) {
        printValue((&value)->first);
        printValue((&value)->second);
    }

    printValue("map55===========================================map55");

    if (container.empty()) {
        printValue(0);
    } else {
        printValue(1);
    }

    printValue("map66===========================================map66");
    //unordered_map的键是唯一的,值可以相同,存在相同的键,后面的会覆盖前面的.
    unordered_map<string, string> unorderedMap;
    unorderedMap["a"] = "1";
    unorderedMap["a"] = "2";
    unorderedMap["a"] = "3";
    unorderedMap["a"] = "4";

    for (auto &value : unorderedMap) {
        printValue((&value)->first);
        printValue((&value)->second);
    }

    //其他的与map相同
}


extern "C"
JNIEXPORT void JNICALL
Java_com_hengfoxwolf_jnidemo_CPlusPlusLearnActivity_setUseFromJNI(JNIEnv *env, jobject thiz) {

    set<string> dataSet;

    printValue("set0===========================================set0");

    //存在相同的值,后面的会覆盖前面的,只保留最后一个.
    dataSet.insert("12");
    dataSet.insert("12");
    dataSet.insert("12");
    dataSet.insert("12");

    //foreach
    for (auto &value: dataSet) {
        printValue(value);
    }

    printValue("set1===========================================set1");

    //迭代器
    for (auto value = dataSet.begin(); value != dataSet.end(); value++) {
        printValue(*value);
    }

    //其他的erase swap  size  clear与map list相同
}


extern "C"
JNIEXPORT void JNICALL
Java_com_hengfoxwolf_jnidemo_CPlusPlusLearnActivity_classTemplateUseFromJNI(JNIEnv *env,jobject thiz) {

    Person<int, float> person(10, 5.0F);
    LOG_D("%f,%d\n",person.data,person.value);

    const char *numberTypeNames[] = {
            typeid(char).name(),
            typeid(bool).name(),
            typeid(int).name(),
            typeid(short).name(),
            typeid(float).name(),
            typeid(long).name(),
            typeid(double).name(),
    };

    jint result = -1;
    jint length = sizeof(numberTypeNames);
    for (int i = 0; i < length; ++i) {
        if (typeid(float).name() == numberTypeNames[i]) {
            result = i;
            break;
        }
    }

    LOG_D("%d\n",result);

}

///////////////////////////////////////////////////////////////////////////////////////////
//函数指针
void func(char **p) {
    char *ch;
    // p += 3 --- p向右移三个元素
    //(p += 3)[-1] --- p先向右移三个元素 再向左移一个元素
    ch = (p += 3)[-1];
    printValue(*p);
    printValue(ch);
}




///////////////////////////////////////////////////////////////////////////////////////////


extern "C"
JNIEXPORT void JNICALL
Java_com_hengfoxwolf_jnidemo_CPlusPlusLearnActivity_pointerUseFromJNI
(JNIEnv *env,
 jobject thiz)
 {

     printValue("pointer0===========================================pointer0");

     //const char *cvalues[] = {
     //     jstr2cstr(env,"one"),
     //     jstr2cstr(env,"two"),
     //     jstr2cstr(env,"three")
     //};
     //jint cchars_length = sizeof(cvalues) / sizeof(const char *);
     //LOG_D("cchars_length=%d",cchars_length);

     char **h;
     char *values[] = {
             StringConvert::jstr2cstr(env,"one"),
             StringConvert::jstr2cstr(env,"two"),
             StringConvert::jstr2cstr(env,"three")
     };

     h = values;
     jint chars_length = sizeof(values) / sizeof(char *);
     LOG_D("chars_length=%d",chars_length);

     for (int i = 0; i < chars_length; ++i) {
         LOG_D("%s\n", *(h++)); //(h++)取出存储在数组中的每一个字符串的地址  *(h++)取出数组中的每一个元素
         //values[0]存放字符串“one”的首字符的地址
         //values[1]存放字符串“two”的首字符的地址
         //values[3]存放字符串“three”的首字符的地址
     }

     printValue("pointer1===========================================pointer1");

     char *arr[] = {
             StringConvert::jstr2cstr(env,"ab"),
             StringConvert::jstr2cstr(env,"cd"),
             StringConvert::jstr2cstr(env,"ef"),
             StringConvert::jstr2cstr(env,"gh"),
             StringConvert::jstr2cstr(env,"ij"),
             StringConvert::jstr2cstr(env,"kl"),
             StringConvert::jstr2cstr(env,"mn")
     };

     func(arr);

     printValue("pointer2===========================================pointer2");

     //数组指针
     int a[5] = {10, 142, 31, 49, 50};
     int (*p)[5];//数组指针
     p = &a;  //指向数组a元素首地址
     LOG_D("p0==%p",&a[0]); //取a[0]元素地址
     LOG_D("p1==%p",&a[1]); //取a[1]元素地址
     LOG_D("p10==%p",p[0]); //取a[0]元素地址
     LOG_D("p11==%p",p[1]); //取a[1]元素地址
     LOG_D("p12==%p",p[2]); //取a[2]元素地址
     LOG_D("p13==%p",p[3]); //取a[3]元素地址
     LOG_D("p14==%p",p[4]); //取a[4]元素地址

     LOG_D("p440==%p",p[4]); //取a[4]元素地址
     LOG_D("p441==%p",(p[0] + 4)); //(p[0] + 4)不等于取a[4]元素地址
     LOG_D("p442==%p",p[0] + 4); // p[0] + 4 不等于取a[4]元素地址,与 (p[0] + 4)等效

     LOG_D("p000088==%d",*a); //a数组名  表示首元素地址  *a表示数组a中的首元素
     LOG_D("p00==%d",*p[0]); //取a[0]元素值----[]的优先级高于*  p先与[]结合形成p[0](a[0]元素地址 即数组a首地址)  再与*结合形成*p[0](a[0]元素值)
     LOG_D("p01==%d",*(p[0] + 1)); //取a[1]元素值
     LOG_D("p03==%d",*(p[0] + 3)); //取a[3]元素值
     LOG_D("p02==%d",*(p[2])); //获取随机值  并不是获取元素值


     printValue("pointer3===========================================pointer3");
     int elements[][3] = { 45, 76, 23,
                           90, 43, 13,
                           92, 56, 89};
     int (*ptr)[3] = elements;  //数组指针指向二维数组
     //elements  elements[0]  ptr  *ptr均表示数组首地址
     LOG_D("00p1--%p",elements);
     LOG_D("00p2--%p",elements[0]);
     LOG_D("000--%p",ptr);
     LOG_D("001--%p",*ptr);

     printValue("pointer4===========================================pointer4");
     // *(ptr[i] + j)  ptr[i][j]  elements[i][j]等效 表示某行某列元数值
     LOG_D("oooo--ptr111=%d",ptr[0][0]);
     LOG_D("oooo--ptr112=%d",elements[0][0]);
     LOG_D("oooo--ptr113=%d",*(ptr[0] + 0));

     LOG_D("o--ptr0=%d",(*ptr)[0]);
     LOG_D("o--ptr1=%d",(*ptr)[1]);

     //二维数组场景下  *ptr[i]   ptr[i]表示第一行元素首地址  *ptr[i]第i行第一个元素
     LOG_D("o11--ptr0=%d",(*ptr[0]));
     LOG_D("o12--ptr1=%d",(*ptr[1]));
     LOG_D("o122--ptr1=%d",(*(ptr[1] + 2)));

     int row = sizeof(elements) / sizeof(elements[0]);
     int col = sizeof(elements[0]) / sizeof(elements[0][0]);
     LOG_D("row=%d",row);
     for (int i = 0; i < row; ++i) {
         for (int j = 0; j < col; ++j) {
             LOG_D("row,col=%d",*(ptr[i] + j));
         }
     }

     //指针移动  表示行地址移动
     ptr++;
     LOG_D("n--ptr0=%d",(*ptr)[0]);
     LOG_D("n--ptr1=%d",(*ptr)[1]);


     printValue("pointer5===========================================pointer5");
     //二维指针函数
     char *data[][4] = {
             StringConvert::jstr2cstr(env,"ab"),StringConvert::jstr2cstr(env,"cd"),StringConvert::jstr2cstr(env,"ef"),StringConvert::jstr2cstr(env,"gh"),
             StringConvert::jstr2cstr(env,"ij"),StringConvert::jstr2cstr(env,"kl"),StringConvert::jstr2cstr(env,"xy"),StringConvert::jstr2cstr(env,"wz"),
     };
     int char_row = (sizeof data) / sizeof(data[0]);
     int char_col = sizeof(data[0]) / sizeof(data[0][0]);
     LOG_D("char_row=%d,char_col=%d",char_row,char_col);
     for (int i = 0; i < char_row; ++i) {
         char **kl = data[i];
         for (int j = 0; j < char_col; ++j) {
             LOG_D("char_value0=%s", *(kl + j));
             LOG_D("char_value1=%s", data[i][j]);
         }
     }

     printValue("pointer6===========================================pointer6");

     char **py;
     py = data[1]; //py = data[i] 表示指针指向第i行的首元素地址
     printValue(*py);
     printValue(*(py + 0)); //*py与*(py + 0)等价 表示第i行的首元素
     py++;//表示指针在某行的前提下向右移动一个单位
     printValue(*(py + 1));
     printValue(*(data[0] + 1));
}